package com.hjj.springboot.service;


import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.hjj.springboot.config.SpoonacularConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class MealPlanService {

    private final SpoonacularConfig config;

    private final RestTemplate restTemplate;

    // 使用Guava Cache实现自动过期
    private final Cache<String, String> dailyCache = CacheBuilder.newBuilder()
            .expireAfterWrite(23, TimeUnit.HOURS) // 缓存23小时保证每日更新
            .maximumSize(100)
            .build();

    //    过敏原添加英文映射
    private static final Map<String, String> mapAllergen;
    static {
        Map<String, String> tempMap = new HashMap<>();
        tempMap.put("乳制品", "dairy");
        tempMap.put("鸡蛋",   "egg");
        tempMap.put("花生",   "peanut");
        tempMap.put("坚果",   "tree nut");
        tempMap.put("海鲜",   "fish");
        mapAllergen = Collections.unmodifiableMap(tempMap);
    }


    //解析过敏原
    private String parseAllergens(List<String> allergens) {
        return allergens.stream()
                .distinct()
                .map(mapAllergen::get)
                .filter(Objects::nonNull)
                .collect(Collectors.joining(","));
    }

    // 构建请求URL
    private String buildRequestUrl(int calories, List<String> allergens) {
        return UriComponentsBuilder.fromHttpUrl(config.getBaseUrl() + config.getMealPlanEndpoint())
                .queryParam("apiKey", config.getKey())
                .queryParam("targetCalories", calories)
                .queryParam("timeFrame", config.getTimeFrame())
                .queryParam("exclude", parseAllergens(allergens))
                .encode()
                .toUriString();
    }


    // 膳食计划获取方法
    public String generateMealPlan(int calories, List<String> allergens) {
        String requestUrl = buildRequestUrl(calories, allergens);
        try {
            return restTemplate.getForObject(requestUrl, String.class);
        } catch (RestClientException e) {
            throw new RuntimeException("连接Spoonacular接口失败", e);
        }
    }

    /**
     * 获取每日膳食计划（智能缓存版）
     * @param date 请求日期（可选）
     * @param calories 每日所需卡路里
     * @param allergens 过敏原列表
     * @return 格式化后的JSON数据
     */
    public String getDailyPlan(String date, int calories, List<String> allergens) {
        LocalDate targetDate = parseDate(date);
        String cacheKey = buildCacheKey(targetDate);

        try {
            return dailyCache.get(cacheKey, () -> {
                log.info("首次请求[{}]的膳食计划，发起API调用", targetDate);
                return fetchFromAPI(calories, allergens);
            });
        } catch (ExecutionException e) {
            log.error("获取膳食计划失败", e);
            return fallbackResponse(); // 添加降级响应
        }
    }

    /**
     * 实际调用API的方法
     */
    private String fetchFromAPI(int calories, List<String> allergens) {
        try {
            String apiResponse = generateMealPlan(calories, allergens);
            log.debug("API调用成功，响应长度：{}", apiResponse.length());
            return apiResponse;
        } catch (Exception e) {
            log.error("Spoonacular API调用失败", e);
            return fallbackResponse(); // 添加降级响应
        }
    }

    /**
     * 降级响应
     */
    private String fallbackResponse() {
        return "膳食计划服务暂时不可用，请稍后重试";
    }

    /**
     * 构建带日期的缓存键（格式：plan_2024-03-15）
     */
    private String buildCacheKey(LocalDate date) {
        return "plan_" + date.toString();
    }

    /**
     * 解析并验证日期参数
     */
    private LocalDate parseDate(String dateStr) {
        try {
            return (dateStr != null) ?
                    LocalDate.parse(dateStr) :
                    LocalDate.now();
        } catch (DateTimeParseException e) {
            log.warn("无效日期格式: {}", dateStr);
            throw new IllegalArgumentException("日期格式应为YYYY-MM-DD");
        }
    }

}
